﻿using System.Data;
using System.Security.Claims;
using Devonline.Communication.Messages;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;

namespace Devonline.Identity.Admin.Controllers;

/// <summary>
/// 角色
/// </summary>    
[Route("api/[controller]")]
[ApiController]
[SecurityHeaders]
[Authorize(Roles = GROUP_MAINTAINERS)]
public class RolesController : ControllerBase
{
    private readonly AdminSetting _appSetting;
    private readonly RoleManager<Role> _roleManager;
    private readonly AuthorizationService _authorizationService;
    private readonly ILogger<RolesController> _logger;
    private readonly IDataWithAttachmentService<Role> _dataService;
    private readonly IMessageCommunicator _communicator;

    public RolesController(
        AdminSetting appSetting,
        RoleManager<Role> roleManager,
        AuthorizationService authorizationService,
        ILogger<RolesController> logger,
        IDataWithAttachmentService<Role> dataService,
        IMessageCommunicator communicator
        )
    {
        _appSetting = appSetting;
        _logger = logger;
        _roleManager = roleManager;
        _dataService = dataService;
        _authorizationService = authorizationService;
        _communicator = communicator;
    }

    [HttpGet, EnableQuery]
    public IActionResult Get() => Ok(_dataService.GetQueryable());
    /// <summary>
    /// 添加角色
    /// </summary>
    /// <param name="viewModel"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<IActionResult> CreateAsync(IdentityViewModel viewModel)
    {
        _logger.LogInformation("user {user} will add the role {role}", _dataService.UserName, viewModel.Name);
        if (await _roleManager.RoleExistsAsync(viewModel.Name))
        {
            return BadRequest($"角色 {viewModel.Name} 已经存在!");
        }

        var role = new Role
        {
            State = viewModel.State,
            Name = viewModel.Name,
            Alias = viewModel.Alias,
            Image = viewModel.Image,
            Type = viewModel.Type,
            NormalizedName = viewModel.Name,
            Description = viewModel.Description
        };

        _dataService.Create(role);
        await _dataService.AddAttachmentsAsync(role, viewModel.Attachments, nameof(Role));
        var result = await _roleManager.CreateAsync(role);
        if (result.Succeeded)
        {
            _logger.LogWarning("user {user} success to add the role {role}", _dataService.UserName, role.Name);
            return Ok();
        }

        var errorMessage = string.Empty;
        if (result.Errors.IsNotNullOrEmpty())
        {
            errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
            _logger.LogWarning("user {user} fail to add the role {role}, error message is: {errorMessage}", _dataService.UserName, role.Name, errorMessage);
        }

        return BadRequest(errorMessage);
    }
    /// <summary>
    /// 修改
    /// </summary>
    /// <param name="viewModel"></param>
    /// <returns></returns>
    [HttpPut]
    public async Task<IActionResult> UpdateAsync(IdentityViewModel viewModel)
    {
        _logger.LogInformation("user {user} will update the user {role}", _dataService.UserName, viewModel);
        var role = await _roleManager.FindByNameAsync(viewModel.Name);
        if (role is null)
        {
            return BadRequest($"角色 {viewModel.Name} 不存在!");
        }

        //不可修改角色名
        //role.Name = viewModel.Name;
        role.Alias = viewModel.Alias;
        role.Image = viewModel.Image;
        role.Type = AuthorizeType.Internal;
        role.Description = viewModel.Description;
        role.Update(_dataService.UserName);
        var result = await _roleManager.UpdateAsync(role);
        if (result.Succeeded)
        {
            _logger.LogWarning("user {user} success to update the role {role}", _dataService.UserName, viewModel.Name);
            return Ok();
        }

        var errorMessage = string.Empty;
        if (result.Errors.IsNotNullOrEmpty())
        {
            errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
            _logger.LogWarning("user {user} fail to update the role {role}, error message is: {errorMessage}", _dataService.UserName, viewModel.Name, errorMessage);
        }

        return BadRequest(errorMessage);
    }

    /// <summary>
    /// 添加角色的一个 Claim
    /// </summary>
    /// <param name="id"></param>
    /// <param name="claim"></param>
    /// <returns></returns>
    [HttpPost("AddClaim/{id}")]
    public async Task<ActionResult> AddClaimAsync(string id, Claim claim)
    {
        _logger.LogInformation("user {user} will add claim to role {role}", _dataService.UserName, id);
        var role = await _roleManager.FindByIdAsync(id);
        if (role == null)
        {
            return BadRequest($"角色 {id} 不存在!");
        }

        var result = await _roleManager.AddClaimAsync(role, claim);
        if (result.Succeeded)
        {
            _logger.LogWarning("user {user} success to add claim to role {role}", _dataService.UserName, role.Name);
            return Ok();
        }

        var errorMessage = string.Empty;
        if (result.Errors.IsNotNullOrEmpty())
        {
            errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
            _logger.LogWarning("user {user} fail to add claim to role {role}, error message is: {errorMessage}", _dataService.UserName, role.Name, errorMessage);
        }

        return BadRequest(errorMessage);
    }
    /// <summary>
    /// 移除角色的一个 Claim
    /// </summary>
    /// <param name="id"></param>
    /// <param name="claim"></param>
    /// <returns></returns>
    [HttpPost("RemoveClaim/{id}")]
    public async Task<ActionResult> RemoveClaimAsync(string id, Claim claim)
    {
        _logger.LogInformation("user {user} will remove claim to role {role}", _dataService.UserName, id);
        var role = await _roleManager.FindByNameAsync(id);
        if (role == null)
        {
            return BadRequest($"角色 {id} 不存在!");
        }

        var result = await _roleManager.RemoveClaimAsync(role, claim);
        if (result.Succeeded)
        {
            _logger.LogWarning("user {user} success to remove claim to role {role}", _dataService.UserName, role.Name);
            return Ok();
        }

        var errorMessage = string.Empty;
        if (result.Errors.IsNotNullOrEmpty())
        {
            errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
            _logger.LogWarning("user {user} fail to remove claim to role {role}, error message is: {errorMessage}", _dataService.UserName, role.Name, errorMessage);
        }

        return BadRequest(errorMessage);
    }
    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteAsync(string id)
    {
        _logger.LogInformation("user {user} will delete the role {role}", _dataService.UserName, id);
        var role = await _roleManager.FindByIdAsync(id);
        if (role is null)
        {
            return BadRequest($"角色 {id} 不存在!");
        }

        if (!string.IsNullOrWhiteSpace(_appSetting.BuiltInRoles))
        {
            var roles = _appSetting.BuiltInRoles.Split(CHAR_COMMA, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
            if (roles.Contains(role.Name) && roles.Contains(role.Name))
            {
                return BadRequest($"内置角色 {role.Name} 不可删除!");
            }
        }

        //此处是逻辑删除, 因此删除后的数据要查询需要带状态条件
        role.State = DataState.Deleted;
        var files = await _dataService.DeleteAttachmentsAsync(id, default, true);
        var result = await _roleManager.UpdateAsync(role);
        if (result.Succeeded)
        {
            _logger.LogWarning("user {user} success to delete the role {role}", _dataService.UserName, role.Name);
            if (files != null && files.Any())
            {
                _dataService.Delete(files);
            }

            return Ok();
        }

        var errorMessage = string.Empty;
        if (result.Errors.IsNotNullOrEmpty())
        {
            errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
            _logger.LogWarning("user {user} fail to delete the role {role}, error message is: {errorMessage}", _dataService.UserName, role.Name, errorMessage);
        }

        return BadRequest(errorMessage);
    }
}